package znet

import (
	"fmt"
	"interstellar/zinx/utils"
	"interstellar/zinx/ziface"
	"net"
)

// iServer的接口实现，定义一个Server的服务器模块

type Server struct {
	// 服务器的名称
	Name string
	// 服务器绑定的ip版本
	IPVersion string
	// 服务器监听的IP
	IP string
	// 服务器监听的端口
	Port int
	//// 当前的Server添加一个router,server注册的链接对应的处理业务
	//Router ziface.IRouter
	// 当前server的消息管理模块，用来绑定msgID和对应的处理业务API关系
	MsgHandler ziface.IMsgHandle
	// 该sever的连接管理器
	ConnMgr ziface.IConnManager
	// 该Server创建链接之后自动调用Hook函数
	OnConnStart func(conn ziface.IConnection)
	// 该Server销毁链接之后自动调用Hook函数
	OnConnStop func(conn ziface.IConnection)
}

//// CallBackToClient 定义当前客户端链接的所绑定handle api(目前这个handle是写死的，以后优化)
//func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
//	// 回显的业务
//	fmt.Println("[Conn Handle] CallBackToClient ... ")
//	if _, err := conn.Write(data[:cnt]); err != nil {
//		fmt.Println("write back buf err", err)
//		return errors.New("CallBackToClient error")
//	}
//
//	return nil
//}

// Start 启动服务器
func (s *Server) Start() {
	fmt.Printf("[Zinx] Server Name: %s, listenner at IP: %s, Port: %d is starting\n",
		utils.GlobalObject.Name, utils.GlobalObject.Host, utils.GlobalObject.TcpPort)
	fmt.Printf("[Zinx] Version %s, MaxConn:%d, MaxPackageSize:%d\n",
		utils.GlobalObject.Version,
		utils.GlobalObject.MaxConn,
		utils.GlobalObject.MaxPackageSize,
	)
	fmt.Printf("[Start] Server Listennet at IP :%s,Port %d, is starting\n", s.IP, s.Port)

	go func() {
		//0 开启消息队列及Worker工作池
		s.MsgHandler.StartWorkerPool()

		//1 获取一个tcp的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("resolve tcp addt error:", err)
			return
		}

		//2 监听服务器的地址
		listennet, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen ", s.IPVersion, "err", err)
			return
		}

		fmt.Println("start Zinx server succ", s.Name, " succ,Listenning..")
		var cid uint32
		cid = 0

		//3 阻塞的等待客户端链接，处理客户端链接业务(读写)
		for {
			// 如果有客服端链接过来，阻塞会返回
			conn, err := listennet.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err", err)
				continue
			}

			//设置最大链接个数的判断，如果超过最大链接，那么则关闭次新的链接
			if s.ConnMgr.Len() >= utils.GlobalObject.MaxConn {
				//TODO 给客户端相应一个超出最大链接的错误包
				fmt.Println("======> Too Many Connections MaxConn = ", utils.GlobalObject.MaxConn)
				conn.Close()
				continue
			}

			// 奖处理新链接的业务方法 和 conn 进行绑定 得到我们的链接模块
			dealConn := NewConnection(s, conn, cid, s.MsgHandler)
			cid++

			// 启动当前的链接业务处理
			go dealConn.Start()

			//// 已经与客户端建立连接，做一些业务,做一个最基本的最大512字节长度的回显业务
			//go func() {
			//	for {
			//		buf := make([]byte, 512)
			//		cnt, err := conn.Read(buf)
			//		if err != nil {
			//			fmt.Println("recv buf err ", err)
			//			continue
			//		}
			//
			//		fmt.Printf("recv client buf %s ,cnt %d\n", buf, cnt)
			//		// 回显功能
			//		if _, err := conn.Write(buf[:cnt]); err != nil {
			//			fmt.Println("write back buf err ", err)
			//			continue
			//		}
			//	}
			//}()
		}
	}()
}

// Stop 停止服务器
func (s *Server) Stop() {
	//TODO 将一些服务器的资源、状态或者一些已经开辟的链接信息 进行停止或者回收
	fmt.Println("[STOP] Zinx server name", s.Name)
	s.ConnMgr.ClearConn()
}

// Serve 运行服务器
func (s *Server) Serve() {
	// 启动server的服务功能
	s.Start()

	//TODO 做一些启动服务器之后的额外业务

	// 阻塞状态
	select {}
}

// AddRouter 路由功能：给当前的服务注册一个路由方法，工客户端的链接处理是用
func (s *Server) AddRouter(msgID uint32, router ziface.IRouter) {
	//s.Router = router
	s.MsgHandler.AddRouter(msgID, router)
	fmt.Println("Add Router Succ!!")
}

// GetConnMgr 获取当前server的链接管理器
func (s *Server) GetConnMgr() ziface.IConnManager {
	return s.ConnMgr
}

/*
	初始化Server模块的方法
*/
func NewServer(name string) ziface.IServer {
	s := &Server{
		Name:      utils.GlobalObject.Name,
		IPVersion: "tcp4",
		IP:        utils.GlobalObject.Host,
		Port:      utils.GlobalObject.TcpPort,
		//Router:    nil,
		MsgHandler: NewMsgHandle(),
		ConnMgr:    NewConnManager(),
	}
	return s
}

// SetOnConnStart 注册OnConnStart 钩子函数的方法
func (s *Server) SetOnConnStart(hookFunc func(connection ziface.IConnection)) {
	s.OnConnStart = hookFunc
}

// SetOnConnStop 注册OnConnStop 钩子函数的方法
func (s *Server) SetOnConnStop(hookFunc func(connection ziface.IConnection)) {
	s.OnConnStop = hookFunc
}

// CallOnConnStart 注册OnConnStart 钩子函数的方法
func (s *Server) CallOnConnStart(conn ziface.IConnection) {
	if s.OnConnStart != nil {
		fmt.Println("---> Call OnConnStart()...")
		s.OnConnStart(conn)
	}
}

// CallOnConnStop 调用OnConnStop 钩子函数的方法
func (s *Server) CallOnConnStop(conn ziface.IConnection) {
	if s.OnConnStop != nil {
		fmt.Println("---> Call OnConnStop()...")
		s.OnConnStop(conn)
	}
}
